home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 051-075 / disk_055 / pipedevice / pipe.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  13KB  |  351 lines

  1.  
  2. /*
  3.  *  PIPE: device driver.
  4.  *
  5.  *  Usage:
  6.  *      The writer opens PIPE:somename and begins writing to it.  The reader
  7.  *      opens PIPE:samename and begins reading from it.  It doesn't matter
  8.  *      who opens PIPE:somename first.  Note that if the writer opens the
  9.  *      handle first, writes <BUFSIZE bytes, then closes, the Close() will
  10.  *      not return until a reader has openned the same pipe.
  11.  *
  12.  *      -Only two opens can be made on a specific pipe
  13.  *      -One of the opens must always write while the other must always
  14.  *       read.
  15.  *
  16.  *      If the reader closed, any further writes will return an error
  17.  *      If the writer closed, any further reads (after the buffer empties)
  18.  *       will return 0.
  19.  *
  20.  *  NOTE:   Like the filesystem DOS device, I assume that no more than one
  21.  *  request for a specific file handle will be queued at a time.  This makes
  22.  *  things a lot easier for me.
  23.  *
  24.  *
  25.  */
  26.  
  27.  
  28. #include <exec/types.h>
  29. #include <exec/nodes.h>
  30. #include <exec/lists.h>
  31. #include <exec/ports.h>
  32. #include <exec/libraries.h>
  33. #include <exec/devices.h>
  34. #include <exec/io.h>
  35. #include <exec/memory.h>
  36. #include <devices/console.h>
  37. #include <libraries/dos.h>
  38. #include <libraries/dosextens.h>
  39. #include <libraries/filehandler.h>
  40.  
  41. typedef struct DosPacket    DOSPACKET;
  42. typedef struct Process      PROC;
  43. typedef struct DeviceNode   DEVNODE;
  44. typedef struct FileHandle   FH;
  45. typedef unsigned char u_char;
  46.  
  47. #define BUFSIZE 4096
  48.  
  49. #undef  BADDR
  50. #define BADDR(x)   ((APTR)((long)x << 2))
  51.  
  52. #define ACTION_FIND_INPUT       1005L
  53. #define ACTION_FIND_OUTPUT      1006L
  54. #define ACTION_END              1007L
  55.  
  56. #define DOS_FALSE    0
  57. #define DOS_TRUE     -1
  58.  
  59. #define ST_EOF      0x01        /*  Handle has been closed      */
  60. #define ST_WPEND    0x04        /*  pending packet is a write   */
  61. #define ST_RPEND    0x08        /*  pending packet is a read    */
  62. #define ST_CPEND    0x10        /*  close pending (writer)      */
  63.  
  64. #define OC_FIRST    1           /*  first open, needs to be another */
  65. #define OC_BOTH     2           /*  both reader and writer open     */
  66. #define OC_LAST     3           /*  one closed, one remaining       */
  67. #define OC_WAITSECOND   4       /*  first open was closed before second was openned */
  68.  
  69.  
  70. extern long AbsExecBase;
  71. extern DOSPACKET *taskwait();
  72. extern char *AllocMem();
  73. long SysBase;
  74.  
  75. typedef struct _PIPE {
  76.     struct _PIPE *next, **prev;
  77.     DOSPACKET *pkt;             /* Current pending packet, if any       */
  78.     char    buf[BUFSIZE];       /* Output Buffer                        */
  79.     char    *name;              /* name (allocated strlen(name)+1)      */
  80.     short   s, e, l;            /* FIFO start, end, size                */
  81.     char    state;              /* Current state                        */
  82.     char    openstate;
  83. } PIPE;
  84.  
  85.  
  86. _main()
  87. {
  88.     PROC        *myproc;     /* my process                             */
  89.     DOSPACKET   *mypkt;      /* a pointer to the dos packet sent       */
  90.     BSTR        parmdevname; /* pointer to device name in parmpkt Arg1 */
  91.     long        parmextra;   /* extra info passed in parmpkt      Arg2 */
  92.     DEVNODE     *mynode;     /* our device node passed in parmpkt Arg3 */
  93.     FH          *fh;         /* a pointer to our file handle           */
  94.     PIPE        *pipe;       /* current PIPE handle                    */
  95.     PIPE        *Pipe = NULL;/* linked list base for all pipes         */
  96.     char        *str;
  97.     u_char      *ptr;
  98.     long        run = TRUE;  /* handler main loop flag                 */
  99.     int         ret;         /* nominal packet return value            */
  100.     int         totalcnt = 0;/* total # active pipes                   */
  101.  
  102.     SysBase = AbsExecBase;
  103.  
  104.     myproc      = (PROC *)FindTask(0L);     /* find myself                  */
  105.     mypkt       = taskwait(myproc);         /*  Wait for startup message    */
  106.     parmdevname = (BSTR)mypkt->dp_Arg1;     /* BSTR name passed to handler  */
  107.     parmextra   = mypkt->dp_Arg2;           /* Extra Info passed            */
  108.     mynode      = (DEVNODE *)BADDR(mypkt->dp_Arg3); /* ptr to device node   */
  109.  
  110.     /* if taskid NOT installed, every ref creates new  */
  111.     /* code must be reentrant                          */
  112.  
  113.     mynode->dn_Task = &myproc->pr_MsgPort;
  114.     returnpkt(mypkt, myproc, DOS_TRUE, mypkt->dp_Res2);
  115.  
  116.     while(run) {
  117.         mypkt = taskwait(myproc);
  118.         ret = DOS_TRUE;
  119.         pipe = (PIPE *)mypkt->dp_Arg1;
  120.  
  121.         switch(mypkt->dp_Type) {
  122.         case ACTION_FIND_INPUT:
  123.         case ACTION_FIND_OUTPUT:
  124.             fh = (FH *)BADDR(mypkt->dp_Arg1);       /* File handle  */
  125.             ptr = (u_char *)BADDR(mypkt->dp_Arg3);  /* File name    */
  126.             str = AllocMem(*ptr + 1, 0);
  127.             if (str == NULL) {
  128.                 ret = DOS_FALSE;
  129.                 goto opfail;
  130.             }
  131.             bmov(ptr+1, str, *ptr);
  132.             str[*ptr] = 0;
  133.             for (pipe = Pipe; pipe; pipe = pipe->next) {
  134.                 if (strcmp(pipe->name, str) == 0) {
  135.                     FreeMem(str, *ptr + 1);
  136.                     goto openok;
  137.                 }
  138.             }
  139.             pipe = (PIPE *)AllocMem(sizeof(PIPE), 0);
  140.             if (pipe == NULL) {
  141.                 ret = DOS_FALSE;
  142.                 FreeMem(str, *ptr + 1);
  143.                 goto opfail;
  144.             }
  145.             ++totalcnt;
  146.  
  147.             bzero(pipe, sizeof(*pipe));
  148.             pipe->l = BUFSIZE;
  149.             pipe->name = str;
  150.             if (Pipe)
  151.                 Pipe->prev = &pipe->next;
  152.             pipe->next = Pipe;
  153.             pipe->prev = &Pipe;
  154.             Pipe = pipe;
  155. openok:
  156.             switch(pipe->openstate) {
  157.             case 0:
  158.                 pipe->openstate = OC_FIRST;
  159.                 break;
  160.             case OC_FIRST:
  161.                 pipe->openstate = OC_BOTH;
  162.                 break;
  163.             case OC_WAITSECOND:
  164.                 pipe->openstate = OC_LAST;
  165.                 pipe->state &= ~ST_CPEND;
  166.                 returnpkt(pipe->pkt, myproc, DOS_TRUE, pipe->pkt->dp_Res2);
  167.                 break;
  168.             case OC_BOTH:
  169.             case OC_LAST:
  170.                 ret = DOS_FALSE;        /* more than 2 opens    */
  171.                 goto opfail;
  172.             }
  173.             fh->fh_Arg1 = (long)pipe;
  174.             fh->fh_Port = (struct MsgPort *)DOS_TRUE;
  175. opfail:
  176.             returnpkt(mypkt, myproc, ret, mypkt->dp_Res2);
  177.             break;
  178.         case ACTION_END:    /*  If pending read, return pend bytes read
  179.                              *  If pending write, return pend bytes written
  180.                              *  return pending message, if any
  181.                              */
  182.             switch(pipe->openstate) {
  183.             case OC_FIRST:
  184.                 pipe->openstate = OC_WAITSECOND;
  185.                 break;
  186.             case OC_BOTH:
  187.                 pipe->openstate = OC_LAST;
  188.                 break;
  189.             case OC_LAST:
  190.                 pipe->openstate = 0;
  191.                 break;
  192.             }
  193.  
  194.             pipe->state |= ST_EOF;
  195.  
  196.             if (pipe->openstate == OC_WAITSECOND) {
  197.                 pipe->pkt = mypkt;
  198.                 pipe->state |= ST_CPEND;
  199.                 break;
  200.             }
  201.  
  202.             if (pipe->state & (ST_RPEND|ST_WPEND)) {
  203.                 returnpktplain(pipe->pkt, myproc);
  204.                 pipe->state &= ~(ST_RPEND|ST_WPEND);
  205.             }
  206.             if (pipe->openstate == 0) {
  207.                 FreeMem(pipe->name, strlen(pipe->name)+1);
  208.                 *pipe->prev = pipe->next;
  209.                 if (pipe->next)
  210.                     pipe->next->prev = pipe->prev;
  211.                 FreeMem(pipe, sizeof(*pipe));
  212.                 --totalcnt;
  213.                 if (totalcnt == 0)
  214.                     run = 0;
  215.             }
  216.             returnpkt(mypkt, myproc, ret, mypkt->dp_Res2);
  217.             break;
  218.         case ACTION_READ:   /*  Take chars from buffer.  If buffer empty
  219.                              *  and read not satisfied, check for pending
  220.                              *  write and take bytes from it's buffer.
  221.                              *  When done, must check to see if buffer will
  222.                              *  hold ALL of pending write.
  223.                              *  When done, if read still is not satisfied,
  224.                              *  make it pending.
  225.                              */
  226.  
  227.             mypkt->dp_Res1 = 0;
  228.  
  229.             /*
  230.              * Load from buffer until empty or read fulfilled
  231.              */
  232.  
  233.             while (pipe->s != pipe->e && mypkt->dp_Res1 != mypkt->dp_Arg3) {
  234.                 int avail = (pipe->s < pipe->e) ?   pipe->e - pipe->s :
  235.                                                     pipe->l - pipe->s;
  236.                 int bytes = mypkt->dp_Arg3 - mypkt->dp_Res1;
  237.                 if (bytes < avail)
  238.                     avail = bytes;
  239.                 bmov(pipe->buf+pipe->s, mypkt->dp_Arg2+mypkt->dp_Res1,avail);
  240.                 pipe->s += avail;
  241.                 mypkt->dp_Res1 += avail;
  242.                 if (pipe->s == pipe->l)
  243.                     pipe->s = 0;
  244.             }
  245.  
  246.             /*
  247.              * If write packet was pending, the read will either exhaust
  248.              * the write and possibly become pending, or not exhaust the
  249.              * write and be returned.
  250.              */
  251.  
  252.             if (mypkt->dp_Res1 != mypkt->dp_Arg3 && (pipe->state & ST_WPEND)) {
  253.                 int bytes = mypkt->dp_Arg3 - mypkt->dp_Res1;
  254.                 int avail = pipe->pkt->dp_Arg3 - pipe->pkt->dp_Res1;
  255.                 if (bytes > avail)
  256.                     bytes = avail;
  257.                 bmov(pipe->pkt->dp_Arg2 + pipe->pkt->dp_Res1, mypkt->dp_Arg2 + mypkt->dp_Res1, bytes);
  258.                 mypkt->dp_Res1 += bytes;
  259.                 pipe->pkt->dp_Res1 += bytes;
  260.                 if (pipe->pkt->dp_Res1 == pipe->pkt->dp_Arg3) {
  261.                     returnpktplain(pipe->pkt, myproc);
  262.                     pipe->state &= ~ST_WPEND;
  263.                 }
  264.             }
  265.  
  266.             /* If read packet is made pending, buffer is always empty   */
  267.  
  268.             if (mypkt->dp_Res1 != mypkt->dp_Arg3 && !(pipe->state&ST_EOF)) {
  269.                 if (pipe->state & (ST_RPEND|ST_WPEND|ST_CPEND)) {
  270.                     returnpkt(pipe->pkt, myproc, DOS_FALSE, ERROR_OBJECT_IN_USE);
  271.                     pipe->state &= ~(ST_RPEND|ST_WPEND|ST_CPEND);
  272.                 }
  273.                 pipe->pkt = mypkt;
  274.                 pipe->state |= ST_RPEND;
  275.             } else {
  276.                 returnpktplain(mypkt, myproc);
  277.             }
  278.             break;
  279.         case ACTION_WRITE:  /*
  280.                              *  If pending read then buffer is empty, place
  281.                              *  chars directly into pending read.  If pending
  282.                              *  write, error.
  283.                              *  If nothing pending and write buffer not big
  284.                              *  enough, make the write pend without filling
  285.                              *  the buffer.  Otherwise, move write data into
  286.                              *  the buffer and return the packet.
  287.                              */
  288.  
  289.             mypkt->dp_Res1 = 0;
  290.  
  291.             if (pipe->state & ST_EOF) {
  292.                 returnpkt(mypkt, myproc, DOS_FALSE, ERROR_SEEK_ERROR);
  293.                 break;
  294.             }
  295.             if (pipe->state & ST_RPEND) {           /* write->read      */
  296.                 int avail = mypkt->dp_Arg3 - mypkt->dp_Res1;
  297.                 int bytes = pipe->pkt->dp_Arg3 - pipe->pkt->dp_Res1;
  298.                 if (avail < bytes)
  299.                     bytes = avail;
  300.                 bmov(mypkt->dp_Arg2+mypkt->dp_Res1, pipe->pkt->dp_Arg2+pipe->pkt->dp_Res1, bytes);
  301.                 mypkt->dp_Res1 += bytes;
  302.                 pipe->pkt->dp_Res1 += bytes;
  303.                 if (pipe->pkt->dp_Res1 == pipe->pkt->dp_Arg3) {
  304.                     returnpktplain(pipe->pkt, myproc);
  305.                     pipe->state &= ~ST_RPEND;
  306.                 }
  307.             }
  308.  
  309.             /*  write into buffer   */
  310.  
  311.             while (mypkt->dp_Res1 != mypkt->dp_Arg3 && pipe->s != ((pipe->e+1)%pipe->l)) {
  312.                 int avail = mypkt->dp_Arg3 - mypkt->dp_Res1;
  313.                 int bytes;
  314.                 if (pipe->e < pipe->s)
  315.                     bytes = pipe->s - pipe->e - 1;
  316.                 else
  317.                     bytes = pipe->l - pipe->e - (pipe->s == 0);
  318.                 if (avail < bytes)
  319.                     bytes = avail;
  320.                 bmov(mypkt->dp_Arg2 + mypkt->dp_Res1, pipe->buf + pipe->e, bytes);
  321.                 pipe->e += bytes;
  322.                 mypkt->dp_Res1 += bytes;
  323.                 if (pipe->e == pipe->l)
  324.                     pipe->e = 0;
  325.             }
  326.  
  327.             if (mypkt->dp_Res1 != mypkt->dp_Arg3) {
  328.                 if (pipe->state & (ST_RPEND|ST_WPEND|ST_CPEND)) {
  329.                     returnpkt(pipe->pkt, myproc, DOS_FALSE, ERROR_OBJECT_IN_USE);
  330.                     pipe->state &= ~(ST_RPEND|ST_WPEND|ST_CPEND);
  331.                 }
  332.                 pipe->pkt = mypkt;
  333.                 pipe->state |= ST_WPEND;
  334.             } else {
  335.                 returnpktplain(mypkt, myproc);
  336.             }
  337.             break;
  338.         default:
  339.             returnpkt(mypkt, myproc, DOS_FALSE, ERROR_ACTION_NOT_KNOWN);
  340.             break;
  341.         }
  342.     }
  343.     mynode->dn_Task = FALSE;
  344.  
  345.     /* we are a process "so we fall off the end of the world" */
  346.     /* MUST fall through */
  347. }
  348.  
  349.  
  350.  
  351.